
/*******************************MILIANKE*******************************
*Company : MiLianKe Electronic Technology Co., Ltd.
*WebSite:https://www.milianke.com
*TechWeb:https://www.uisrc.com
*tmall-shop:https://milianke.tmall.com
*jd-shop:https://milianke.jd.com
*taobao-shop1: https://milianke.taobao.com
*Create Date: 2022/05/15
*File Name: 
*Description: 
*Declaration:
*The reference demo provided by Milianke is only used for learning. 
*We cannot ensure that the demo itself is free of bugs, so users 
*should be responsible for the technical problems and consequences
*caused by the use of their own products.
*Copyright: Copyright (c) MiLianKe
*All rights reserved.
*Revision: 1.0
*Signal description
*1) _i input
*2) _o output
*3) _n activ low
*4) _dg debug signal 
*5) _r delay or register
*6) _s state mechine
*********************************************************************/
`timescale 1ns / 1ps

`define   DATA_WIDTH                        32										// 数据位宽
`define   ADDR_WIDTH                        21										// 地址位宽
`define   DM_WIDTH                          4										// 数据掩码位宽
`define   ROW_WIDTH                         11										// 行地址位宽
`define   BA_WIDTH                          2										// Bank位宽
`define	  SDR_CLK_PERIOD				1000000000/150000000						// SDRAM时钟周期
`define   SELF_REFRESH_INTERVAL			64000000/`SDR_CLK_PERIOD/2**(`ROW_WIDTH) 	// SDRAM自刷新时间

module eg4d_sram_fdma_test#
(
	parameter  integer TEST_MEM_SIZE  	   	 = 32'd640*480,			// SDR读写总内存大小 单位 字 SDRAM内存 2M 字
	parameter  integer TEST_MEN_ADDR_OFFSET  = 16'd0,				// FDMA地址偏移 单位 字
	parameter  integer FDMA_BURST_LEN        = 16'd640				// FDMA突发传输长度 单位 字
)
(
	input 	wire								i_clk,				// 系统时钟
	input	wire								i_rst_n,			// 系统低电平复位信号
	output	wire								o_fdma_clk,			// FDMA时钟
	input	wire								udp_clk,
	input   wire                                udp_data_valid, 	// 以太网接收数据有效信号
    input   wire    [7 : 0]                     udp_data,       	// 以太网接收数据
	input 	wire								hdmi_clk,
	output 	wire								O_led1,
	output	wire								O_led2 
);

wire 								CLK  	;
wire 								RAS_N	;
wire 								CAS_N	;
wire 								WE_N 	;
wire	[`BA_WIDTH - 1 : 0]			BA   	;
wire 	[`ROW_WIDTH - 1 : 0]		ADDR 	;
wire 	[`DM_WIDTH - 1 : 0]			DM   	;
wire 	[`DATA_WIDTH - 1 : 0]		DQ   	;

wire								lock                ;
wire								rst_n               ;
wire								clk0                ;
wire								clk90               ;
wire								clk180              ;

wire 								sdr_init_done       ;
wire 								sdr_init_ref_vld    ;
wire 								app_wr_en           ;
wire 	[`ADDR_WIDTH - 1 : 0]		app_wr_addr         ;//synthesis keep
wire 	[`DM_WIDTH - 1 : 0]			app_wr_dm           ;//synthesis keep
wire 	[`DATA_WIDTH - 1 : 0]		app_wr_din          ;//synthesis keep
wire 								app_rd_en           ;//synthesis keep
wire 	[`ADDR_WIDTH - 1 : 0]		app_rd_addr         ;//synthesis keep
wire 								sdr_rd_en           ;//synthesis keep
wire 	[`DATA_WIDTH - 1 : 0]		sdr_rd_dout         ;//synthesis keep
wire            					sdr_busy			;

wire 	[20 : 0] 					fdma_waddr          ;
wire  	     						fdma_wareq          ;
wire 	[15 : 0] 					fdma_wsize          ;                                    
wire         						fdma_wbusy          ;	
wire 	[31  :0] 					fdma_wdata			;//synthesis keep
wire         						fdma_wvalid         ;
							
wire 	[20 : 0] 					fdma_raddr          ;
wire         						fdma_rareq          ;
wire 	[15 : 0] 					fdma_rsize          ;                                 
wire         						fdma_rbusy          ;
wire 	[31  :0] 					fdma_rdata			;
wire         						fdma_rvalid         ;
							
wire								fdma_error			;

assign O_led1  = sdr_init_done & ~fdma_error;
assign O_led2  = ~sdr_init_done ;

assign rst_n = !lock;
wire					fdma_clk = clk0;
wire					fdma_clk180 = clk180;
assign 					o_fdma_clk = fdma_clk;
//////////////////////////////////////////////////////////////////////////////////////
// 产生150MHz读写时钟
fdma_pll u_clk(
	.refclk             (i_clk      	),
	.reset              (!i_rst_n    	),
	.extlock            (lock           ),
	.clk0_out           (clk0           ),		//150.000000MHZ	| 0  DEG 
	.clk1_out           (clk90          ),		//150.000000MHZ	| 90 DEG 
	.clk2_out           (clk180         )		//150.000000MHZ	| 180DEG 
);

// output declaration of module udp_fdma_ddr_rx_buff
wire fifo_rd_req;
wire fifo_rd_valid;
wire [31:0] fifo_rd_data;
wire [20:0] sdr_waddr;
wire [15:0] sdr_wsize;

// outports wire
localparam M_AXI_DATA_WIDTH = 21;
localparam M_AXI_ADDR_WIDTH = 32;

wire                        	user_wdata_done;
wire                        	user_rdata_valid;
wire [M_AXI_DATA_WIDTH-1:0] 	user_rdata;
wire                        	user_rdata_done;
wire                        	fdma_wready;
wire                        	fdma_rready;

// output declaration of module udp_fdma_ddr_tx_buff
wire fifo_wr_req;
wire [31:0] sdr_raddr;
wire [15:0] sdr_rsize;
wire hdmi_data_valid;
wire [23:0] hdmi_data;

udp_fdma_ddr_rx_buff #(
	.MEM_SIZE   	(640*480  ),
	.BURST_SIZE 	(512  ))
u_udp_fdma_ddr_rx_buff(
	.i_wr_clk       	(udp_clk        ),
	.i_rd_clk       	(fdma_clk        ),
	.i_rst_n        	(i_rst_n & lock & sdr_init_done        ),
	.udp_data_valid 	(udp_data_valid  ),
	.udp_data       	(udp_data        ),
	.fifo_rd_req    	(fifo_rd_req     ),
	.fifo_rd_valid  	(fifo_rd_valid   ),
	.fifo_rd_data   	(fifo_rd_data    ),
	.sdr_waddr      	(sdr_waddr       ),
	.sdr_wsize      	(sdr_wsize       ),
	.sdr_wdata_done 	(user_wdata_done  )
);

udp_fdma_ddr #(
	.TEST_MEM_SIZE        	( 640*480  ),
	.TEST_MEN_ADDR_OFFSET 	( 0  ),
	.FDMA_BURST_LEN       	( 512  ),
	.M_AXI_ADDR_WIDTH     	( 21   ),
	.M_AXI_DATA_WIDTH     	( 32   ))
u_udp_fdma_ddr(
	.user_wdata_req   	( fifo_rd_req    	),
	.user_wdata_valid 	( fifo_rd_valid  	),
	.user_wdata       	( fifo_rd_data      ),
	.user_waddr       	( sdr_waddr        	),
	.user_wsize       	( sdr_wsize         ),
	.user_wdata_done  	( user_wdata_done   ),
	.user_rdata_req   	( fifo_wr_req    	),
	.user_rdata_valid 	( user_rdata_valid  ),
	.user_rdata       	( user_rdata        ),
	.user_raddr       	( sdr_raddr        	),
	.user_rsize       	( sdr_rsize        	),
	.user_rdata_done  	( user_rdata_done   ),
	.sdr_busy         	( sdr_busy          ),
	.fdma_clk         	( fdma_clk          ),
	.fdma_rstn        	( i_rst_n & lock & sdr_init_done    ),
	.fdma_waddr       	( fdma_waddr        ),
	.fdma_wareq       	( fdma_wareq        ),
	.fdma_wsize       	( fdma_wsize        ),
	.fdma_wbusy       	( fdma_wbusy        ),
	.fdma_wdata       	( fdma_wdata        ),
	.fdma_wvalid      	( fdma_wvalid       ),
	.fdma_wready      	( fdma_wready       ),
	.fdma_raddr       	( fdma_raddr        ),
	.fdma_rareq       	( fdma_rareq        ),
	.fdma_rsize       	( fdma_rsize        ),
	.fdma_rbusy       	( fdma_rbusy        ),
	.fdma_rdata       	( fdma_rdata        ),
	.fdma_rvalid      	( fdma_rvalid       ),
	.fdma_rready      	( fdma_rready       )
);

udp_fdma_ddr_tx_buff #(
	.MEM_SIZE   	(640*480  ),
	.BURST_SIZE 	(512  ))
u_udp_fdma_ddr_tx_buff(
	.i_wr_clk        	(fdma_clk         ),
	.i_rd_clk        	(hdmi_clk         ),
	.i_rst_n         	(i_rst_n & lock & sdr_init_done         ),
	.fifo_wr_req     	(fifo_wr_req      ),
	.fifo_wr_valid   	(user_rdata_valid    ),
	.fifo_wr_data    	(user_rdata     ),
	.sdr_raddr       	(sdr_raddr        ),
	.sdr_rsize       	(sdr_rsize        ),
	.sdr_rdata_done  	(user_rdata_done   ),
	.hdmi_data_valid 	(hdmi_data_valid  ),
	.hdmi_data       	(hdmi_data        )
);

//////////////////////////////////////////////////////////////////////////////////////
// 米联客FDMA IP核 将fdma信号转为app信号供sdr_as_ram模块使用
app_fdma#(
	.APP_ADDR_WIDTH     (`ADDR_WIDTH),
	.APP_DATA_WIDTH     (`DATA_WIDTH),
	.APP_DATA_DM      	(`DM_WIDTH)
) app_fdma_inst
(
	.fdma_clk      		(fdma_clk) 	    ,
	.fdma_rstn          (sdr_init_done) ,
	//===========fdma interface=======  
	.fdma_waddr        (fdma_waddr)     ,
	.fdma_wareq        (fdma_wareq)     ,
	.fdma_wsize        (fdma_wsize)     ,                                
	.fdma_wbusy        (fdma_wbusy)     ,
	.fdma_wdata		   (fdma_wdata)     ,
	.fdma_wvalid       (fdma_wvalid)    ,
														
	.fdma_raddr        (fdma_raddr)     ,
	.fdma_rareq        (fdma_rareq)     ,
	.fdma_rsize        (fdma_rsize)     ,                                
	.fdma_rbusy        (fdma_rbusy)     ,
	.fdma_rdata		   (fdma_rdata)     ,
	.fdma_rvalid       (fdma_rvalid)	,

	//===========ddr interface===============
	.sdr_init_done   	(sdr_init_done)	,
	.sdr_init_ref_vld	(sdr_init_ref_vld)  ,
											
	.app_wr_en       	(app_wr_en)     ,
	.app_wr_addr     	(app_wr_addr)   ,
	.app_wr_dm       	(app_wr_dm)     ,
	.app_wr_din     	(app_wr_din)    ,
										
	.app_rd_en       	(app_rd_en)     ,
	.app_rd_addr     	(app_rd_addr)   ,
	.sdr_rd_en       	(sdr_rd_en)     ,
	.sdr_rd_dout        (sdr_rd_dout)   ,
	.sdr_busy			(sdr_busy)      
);

//////////////////////////////////////////////////////////////////////////////////////
// 将SDRAM控制器接口封装成类似于RAM接口的模块
// 用于简化上层逻辑对SDRAM的访问
sdr_as_ram  
#( 
	.self_refresh_open(1'b1)
) u2_ram( 
	.Sdr_clk(fdma_clk),
	.Sdr_clk_sft(fdma_clk180),
	.Rst(rst_n ),
						
	.Sdr_init_done(sdr_init_done),
	.Sdr_init_ref_vld(Sdr_init_ref_vld),
	.Sdr_busy(sdr_busy),
	
	.App_ref_req(1'b0),
	
	.App_wr_en(app_wr_en), 
	.App_wr_addr(app_wr_addr),  	
	.App_wr_dm(app_wr_dm),
	.App_wr_din(app_wr_din),

	.App_rd_en(app_rd_en),
	.App_rd_addr(app_rd_addr),
	.Sdr_rd_en	(sdr_rd_en),
	.Sdr_rd_dout(sdr_rd_dout),

	.SDRAM_CLK(CLK),
	.SDR_RAS(RAS_N),
	.SDR_CAS(CAS_N),
	.SDR_WE(WE_N),
	.SDR_BA(BA),
	.SDR_ADDR(ADDR),
	.SDR_DM(DM),
	.SDR_DQ(DQ)	
);

//////////////////////////////////////////////////////////////////////////////////////
// 片内嵌入式SDRAM 只需例化IP核，而不用引出信号，即可对SDRAM进行读写操作
// EG_PHY_SDRAM_2M_32 sdram(
// 	.clk(CLK),
// 	.ras_n(RAS_N),
// 	.cas_n(CAS_N),
// 	.we_n(WE_N),
// 	.addr(ADDR[10:0]),
// 	.ba(BA),
// 	.dq(DQ),
// 	.cs_n(1'b0),
// 	.dm0(DM[0]),
// 	.dm1(DM[1]),
// 	.dm2(DM[2]),
// 	.dm3(DM[3]),
// 	.cke(1'b1)
// );
IS42s32200 sdram(
	.Clk(CLK),
	.Ras_n(RAS_N),
	.Cas_n(CAS_N),
	.We_n(WE_N),
	.Addr(ADDR[10:0]),
	.Ba(BA),
	.Dq(DQ),
	.Cs_n(1'b0),
	.Dqm(DM),
	.Cke(1'b1)
);
endmodule